#include "Quad.h"

//********************************************************************************************
// constructor
//
//********************************************************************************************
Quad::Quad(camera * cam)
{
	this->cam = cam;
}


Quad::~Quad(void){}

//********************************************************************************************
// quad to string on cout
//
//********************************************************************************************
void Quad::toString()
{
	for(unsigned int i =0; i<zones.size(); i++)
		zones.at(i).toString();
}

//********************************************************************************************
// import the quad from file
//
//********************************************************************************************
void Quad::import(char* file)
{
    ifstream fichier(file);

    if(fichier)
    {
        string ligne;
        Zone zone;
        vector<short> faces;
        vector<struct CUSTOMVERTEX> points;

		// get min and max height
        this->min = atof(ligne.c_str());
        this->max = atof(ligne.c_str());

        while(getline(fichier, ligne))
        {
			// get the zone
            if (ligne.compare("<zone>") == 0)
            {
                
                getline(fichier, ligne);
                float x = atof(ligne.c_str());
                getline(fichier, ligne);
                float y = atof(ligne.c_str());
                getline(fichier, ligne);
                float size = atof(ligne.c_str());

                zone = Zone(x,y,size);
                faces.clear();
                points.clear();
            }
			// save the zone
            else if (ligne.compare("</zone>") == 0)
            {
                

                int size = faces.size();
                short * indices = new short[size];

                for (int i = 0 ; i < size ; i++) {
                    indices[i] = faces[i];
                }

                zone.setNbIndices(size);
                zone.setIndices(indices);

                size = points.size();
                CUSTOMVERTEX * vertices = new CUSTOMVERTEX[size];

                for (int i = 0 ; i < size ; i++) {
                    vertices[i] = points[i];
                }

                zone.setNbVertices(size);
                zone.setVertices(vertices);

				zone.initialize();

                zones.push_back(zone);
            }
			// get the indices
            else if (ligne.compare("		<t>") == 0)
            {
                
                getline(fichier, ligne);
                faces.push_back(atoi(ligne.c_str())-1);
                getline(fichier, ligne);
                faces.push_back(atoi(ligne.c_str())-1);
                getline(fichier, ligne);
                faces.push_back(atoi(ligne.c_str())-1);
            }
            else if (ligne.compare("		</t>") == 0)
            {

            }
			// get the vertices
            else if (ligne.compare("		<p>") == 0)
            {
                
                getline(fichier, ligne);
                float x = atof(ligne.c_str());
                getline(fichier, ligne);
                float z = atof(ligne.c_str());
                getline(fichier, ligne);
                float y = atof(ligne.c_str());

                getline(fichier, ligne);
                float xv = atof(ligne.c_str());
                getline(fichier, ligne);
                float yv = atof(ligne.c_str());
                getline(fichier, ligne);
                float zv = atof(ligne.c_str());

                CUSTOMVERTEX tmp = {x, y, z, xv, yv, zv, D3DCOLOR_XRGB(150, 150, 150)};
                points.push_back(tmp);

            }
            else if (ligne.compare("		</p>") == 0)
            {

            }
        }

		// close the file
		fichier.close();
    }
    else
    {
        cout << "ERREUR: Impossible d'ouvrir le fichier en lecture." << endl;
    }
}

//********************************************************************************************
// render the quad
//
//********************************************************************************************
void Quad::render()
{
	// create the material for drawing the scene
    D3DMATERIAL9 material;
	ZeroMemory(&material, sizeof(D3DMATERIAL9));
    material.Diffuse = D3DXCOLOR(0.8f, 0.8f, 0.8f, 1.0f);
    material.Ambient = D3DXCOLOR(0.5f, 0.5f, 0.5f, 0.5f);
    d3ddev->SetMaterial(&material);    // set the globably-used material to &material

	// return to the center of the world
	D3DXMATRIX matTranslate;
	D3DXMatrixTranslation(&matTranslate, 0.0f, 0.0f, 0.0f);
    d3ddev->SetTransform(D3DTS_WORLD, &(matTranslate));

	for(unsigned int i =0 ; i<this->zones.size(); i++)
	{
		// check if the zone is visible and render it
		if(zoneVisible(&this->zones.at(i)))
			zones.at(i).render();
	}
	
}

//********************************************************************************************
// release the quad
//
//********************************************************************************************
void Quad::release()
{
	for(unsigned int i =0 ; i<this->zones.size(); i++)
	{
		this->zones.at(i).release();
	}
	
}

//********************************************************************************************
// check if a zone is visible
//
//********************************************************************************************
bool Quad::zoneVisible(Zone * z)
{
	// for the points of the cube
	if(cam->pointInFrustum(&D3DXVECTOR3(z->getX(), this->min, z->getY())))
		return TRUE;
	if(cam->pointInFrustum(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY())))
		return TRUE;
	if(cam->pointInFrustum(&D3DXVECTOR3(z->getX(), this->min, z->getY()+z->getSize())))
		return TRUE;
	if(cam->pointInFrustum(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()+z->getSize())))
		return TRUE;

	if(cam->pointInFrustum(&D3DXVECTOR3(z->getX(), this->max, z->getY())))
		return TRUE;
	if(cam->pointInFrustum(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY())))
		return TRUE;
	if(cam->pointInFrustum(&D3DXVECTOR3(z->getX(), this->max, z->getY()+z->getSize())))
		return TRUE;
	if(cam->pointInFrustum(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()+z->getSize())))
		return TRUE;


	bool ret = TRUE;

	// if all the points are outside of one and only plane
	if(cam->outsideRightPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()))
		&& cam->outsideRightPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()))
		&& cam->outsideRightPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()+z->getSize()))
		&& cam->outsideRightPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()+z->getSize()))
		&& cam->outsideRightPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()))
		&& cam->outsideRightPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()))
		&& cam->outsideRightPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()+z->getSize()))
		&& cam->outsideRightPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()+z->getSize())))
		ret = FALSE;

	if(cam->outsideLeftPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()))
		&& cam->outsideLeftPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()))
		&& cam->outsideLeftPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()+z->getSize()))
		&& cam->outsideLeftPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()+z->getSize()))
		&& cam->outsideLeftPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()))
		&& cam->outsideLeftPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()))
		&& cam->outsideLeftPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()+z->getSize()))
		&& cam->outsideLeftPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()+z->getSize())))
		ret = FALSE;

	if(cam->outsideTopPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()))
		&& cam->outsideTopPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()))
		&& cam->outsideTopPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()+z->getSize()))
		&& cam->outsideTopPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()+z->getSize()))
		&& cam->outsideTopPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()))
		&& cam->outsideTopPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()))
		&& cam->outsideTopPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()+z->getSize()))
		&& cam->outsideTopPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()+z->getSize())))
		ret = FALSE;

	if(cam->outsideBottomPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()))
		&& cam->outsideBottomPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()))
		&& cam->outsideBottomPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()+z->getSize()))
		&& cam->outsideBottomPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()+z->getSize()))
		&& cam->outsideBottomPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()))
		&& cam->outsideBottomPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()))
		&& cam->outsideBottomPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()+z->getSize()))
		&& cam->outsideBottomPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()+z->getSize())))
		ret = FALSE;

	if(cam->outsideFarPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()))
		&& cam->outsideFarPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()))
		&& cam->outsideFarPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()+z->getSize()))
		&& cam->outsideFarPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()+z->getSize()))
		&& cam->outsideFarPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()))
		&& cam->outsideFarPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()))
		&& cam->outsideFarPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()+z->getSize()))
		&& cam->outsideFarPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()+z->getSize())))
		ret = FALSE;

	if(cam->outsideNearPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()))
		&& cam->outsideNearPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()))
		&& cam->outsideNearPlane(&D3DXVECTOR3(z->getX(), this->min, z->getY()+z->getSize()))
		&& cam->outsideNearPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->min, z->getY()+z->getSize()))
		&& cam->outsideNearPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()))
		&& cam->outsideNearPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()))
		&& cam->outsideNearPlane(&D3DXVECTOR3(z->getX(), this->max, z->getY()+z->getSize()))
		&& cam->outsideNearPlane(&D3DXVECTOR3(z->getX()+z->getSize(), this->max, z->getY()+z->getSize())))
		ret = FALSE;

	return ret;
}

//********************************************************************************************
// render the zone i
//
//********************************************************************************************
void Quad::renderZone(int i)
{
	zones.at(i).render();
}